<?php  
	if ( ! defined('BASEPATH')) exit('No direct script access allowed');
	/**
	 * CodeIgniter
	 * @package		CodeIgniter
	 * @subpackage	Libraries
	 * @author		AnhDT
	 */

	class st_paginator implements Countable, IteratorAggregate {
		// Kiểu trượt trang
		protected static $_defaultScrolling = 'slider';
		// Tiền tố của lớp trượt trang
		protected static $_prefixScrolling = 'st_paginator_scrolling_';
		// Tiền tố của lớp engine
		protected static $_prefixEngine    = 'st_paginator_engine_';
		// Lớp phân trang
		protected $_engine = null;
		// Lớp trượt trang
		protected $_scrolling = null;	
		// Số lượng các phần từ trong trang hiện tại
		protected $_currentItemCount = null;
		// Các phần từ trong trang hiện tại
		protected $_currentItems = null;
		// Chỉ mục trang hiện tại
		protected $_currentPageIndex = 1;
		// Số lượng các phần từ có trong mỗi trang
		protected $_itemCountPerPage = 4;
		// Số lượng các trang
		protected $_pageCount = null;
		// Khoảng cách trượt
		protected $_pageRange = 5;
		// Các trang
		protected $_pages = null;
		
		public function __construct(st_paginator_engine_interface $_engine = null) {
			if (null !== $_engine) {
				$this->_engine = $_engine;
			}
		}
		
		/**Thiết lập tiền tố trượt trang*/
		public function setPrefixScrolling($_prefix = '') {
			if (!empty($_prefix)) {
				self::$_prefixScrolling = $_prefix;
			}
			return $this;
		}
		
		/**Lấy về tiền tố trượt trang*/
		public function getPrefixScrolling() {
			return (string)self::$_prefixScrolling;	
		}
		
		/**Thiết lập tiền tố engine*/
		public function setPrefixEngine($_prefix = '') {
			if (!empty($_prefix)) {
				self::$_prefixEngine = $_prefix;	
			}	
			return $this;
		}
		
		/**Lấy về tiền tố engine*/
		public function getPrefixEngine() {
			return (string)self::$_prefixEngine;	
		}
		
		/**Lấy về kiểu trượt chỉ mục mặc định*/
		public static function getDefaultScrolling() {
			return self::$_defaultScrolling;
		}
		/**Thiết lập kiểu trượt chỉ mục mặc định*/
		public static function setDefaultScrolling($_scrollingType = 'slider') {
			self::$_defaultScrolling = $_scrollingType;
		}
		
		/**
		 * Trả về số lượng các trang
		 * @return integer
		 */
		public function count() {
			if (!$this->_pageCount) {
				$this->_pageCount = $this->_calculatePageCount();
			}
			return $this->_pageCount;
		}
	
		/**
		 * Trả về số lượng các phần từ có sẵn
		 * @return integer
		 */
		public function getTotalItemCount() {
			return count($this->_scrolling);
		}

		/**
		 * Trả về kiểu phân trang: collection, array...
		 * @return st_paginator_engine_interface
		 */
		public function getEngine() {
			return $this->_engine;
		}
		
		/**
		 * Thiết lập kiểu phân trang: collection, array...
		 * @return st_paginator
		 */
		public function setEngine(st_paginator_engine_interface $_engine) {
			$this->_engine = $_engine;
			return $this;
		}
	
		/**
		 * Trả về số lượng các phần từ có trong trang hiện tại
		 * @return integer
		 */
		public function getCurrentItemCount() {
			if ($this->_currentItemCount === null) {
				$this->_currentItemCount = $this->getItemCount($this->getCurrentItems());
			}
			return $this->_currentItemCount;
		}
	
		/**
		 * Lấy về các phần từ trong trang hiện tại
		 * @return Traversable
		 */
		public function getCurrentItems() {
			if ($this->_currentItems === null) {
				$this->_currentItems = $this->getItemsByPage($this->getCurrentPageNumber());
			}
			return $this->_currentItems;
		}
	
		/**
		 * Lấy về chỉ mục trang hiện thời
		 * @return integer
		 */
		public function getCurrentPageNumber() {
			return $this->renderPageNumber($this->_currentPageIndex);
		}
	
		/**
		 * Thiết lập trang hiện thời
		 * @param  integer $_pageNumber Page number
		 * @return Zend_Paginator $this
		 */
		public function setCurrentPageNumber($_pageNumber) {
			$this->_currentPageIndex = (integer) $_pageNumber;
			$this->_currentItems      = null;
			$this->_currentItemCount  = null;
			return $this;
		}
	
		/**
		 * Trả về số lượng các phần từ có trong mỗi trang
		 * @return integer
		 */
		public function getItemCountPerPage() {
			return $this->_itemCountPerPage;
		}
	
		/**
		 * Thiết lập số phần từ có trong mỗi trang
		 * @param  integer $_itemCountPerPage
		 * @return Zend_Paginator $this
		 */
		public function setItemCountPerPage($_itemCountPerPage) {
			$this->_itemCountPerPage = (integer) $_itemCountPerPage;
			if ($this->_itemCountPerPage == 0) {
				$this->_itemCountPerPage = 1;
			}
			$this->_pageCount  = $this->_calculatePageCount();
			$this->_currentItems     = null;
			$this->_currentItemCount = null;
			return $this;
		}
	
		/**
		 * Trả về số phần từ có trong tập hợp
		 * @param  mixed $items Items
		 * @return integer
		 */
		public function getItemCount($items) {
			$itemCount = 0;       
			if (is_array($items) or $items instanceof Countable) {
				$itemCount = count($items);
			}
			return $itemCount;
		}
		
		/**
		 * Trả về phần tử trong một trang, sẽ lấy trang hiện thời nếu chỉ
		 * mục của trang không được chỉ ra
		 * @param  integer $_itemNumber Item number (1 to itemCountPerPage)
		 * @param  integer $_pageNumber
		 * @return mixed
		 */
		public function getItem($_itemNumber, $_pageNumber = null) {
			$_itemNumber = $this->renderItemNumber($_itemNumber);       
			if ($_pageNumber == null) {
				$_pageNumber = $this->getCurrentPageNumber();
			}
			$page      = $this->getItemsByPage($_pageNumber);
			$itemCount = $this->getItemCount($page);
			if ($itemCount == 0 || $_itemNumber > $itemCount) {
				return false;
			}
			return $page[$_itemNumber - 1];
		}
	
		/**
		 * Returns the items for a given page.
		 *
		 * @return Traversable
		 */
		public function getItemsByPage($_pageNumber) {
			$_pageNumber = $this->renderPageNumber($_pageNumber);
			$offset = ($_pageNumber - 1) * $this->_itemCountPerPage;	
			$items = $this->_engine->getItems($offset, $this->_itemCountPerPage);
			return $items;
		}
	
		/**
		 * Lấy về bộ duyệt cho các phần từ có trong trang hiện tại
		 * @return Traversable
		 */
		public function getIterator() {
			return $this->getCurrentItems();
		}
	
		/**
		 * Lấy về khoảng cách trượt trang
		 * @return integer
		 */
		public function getPageRange() {
			return $this->_pageRange;
		}
	
		/**
		 * Thiết lập khoảng cách trượt trang
		 * @param  integer $_pageRange
		 * @return Zend_Paginator $this
		 */
		public function setPageRange($_pageRange) {
			$this->_pageRange = (integer)$_pageRange;
			return $this;
		}
	
		/**
		 * Trả về tập hợp các trang
		 * @param  string $_scrollingType Scrolling style
		 * @return array
		 */
		public function getPages($_scrollingType) {
			if ($this->_pages === null) {
				$this->_pages = $this->_createPages($_scrollingType);
			}
			return $this->_pages;
		}
	
		/**
		 * Lấy về các trang trong một khoảng
		 * @param  integer $lowerBound Lower bound of the range
		 * @param  integer $upperBound Upper bound of the range
		 * @return array
		 */
		public function getPagesInRange($lowerBound, $upperBound) {
			$lowerBound = $this->renderPageNumber($lowerBound);
			$upperBound = $this->renderPageNumber($upperBound);
			$pages = array();			
			for ($_pageNumber = $lowerBound; $_pageNumber <= $upperBound; $_pageNumber++) {
				$pages[$_pageNumber] = $_pageNumber;
			}
			return $pages;
		}
	
		/**
		 * Chuẩn hóa lại giá trị số trong độ dài của trang.
		 * @param  integer $_itemNumber
		 * @return integer
		 */
		protected function renderItemNumber($_itemNumber) {
			$_itemNumber = ($_itemNumber < 1) ? 1 : $_itemNumber; 
			$_itemNumber = ($_itemNumber > $this->_itemCountPerPage) ? $_itemNumber = $this->_itemCountPerPage : $_itemNumber;
			return $_itemNumber;
		}
	
		/**Chuẩn hóa lại giá trị chỉ mục của trang
		 * @param  integer $_pageNumber
		 * @return integer
		 */
		protected function renderPageNumber($_pageNumber) {
			$_pageNumber = ($_pageNumber < 1) ? 1 : $_pageNumber;
			$_pageCount = $this->count();       
			if ($_pageCount > 0 and $_pageNumber > $_pageCount) {
				$_pageNumber = $_pageCount;
			}
			return $_pageNumber;
		}
	
		/**
		 * Tính toán số tổng số trang
		 * @return integer
		 */
		protected function _calculatePageCount() {
			return (integer) ceil($this->_engine->count() / $this->_itemCountPerPage);
		}
	
		/**
		 * Tạo ra tập hợp các trang
		 * @param  string $_scrollingType Scrolling style
		 * @return stdClass
		 */
		protected function _createPages($_scrollingType = null) {
			$_pageCount         = $this->count();
			$_currentPageNumber = $this->getCurrentPageNumber();
			
			$pages = new stdClass();
			$pages->pageCount        = $_pageCount;
			$pages->itemCountPerPage = $this->getItemCountPerPage();
			$pages->first            = 1;
			$pages->current          = $_currentPageNumber;
			$pages->last             = $_pageCount;
	
			// Previous and next
			if ($_currentPageNumber - 1 > 0) {
				$pages->previous = $_currentPageNumber - 1;
			}
	
			if ($_currentPageNumber + 1 <= $_pageCount) {
				$pages->next = $_currentPageNumber + 1;
			}
	
			// Pages in range
			$_scrollingType = $this->_loadScrolling($_scrollingType);
			$pages->pagesInRange     = $_scrollingType->getPages($this);
			$pages->firstPageInRange = min($pages->pagesInRange);
			$pages->lastPageInRange  = max($pages->pagesInRange);
	
			// Item numbers
			if ($this->getCurrentItems() !== null) {
				$pages->currentItemCount = $this->getCurrentItemCount();
				$pages->itemCountPerPage = $this->getItemCountPerPage();
				$pages->totalItemCount   = $this->getTotalItemCount();
				$pages->firstItemNumber  = (($_currentPageNumber - 1) * $this->_itemCountPerPage) + 1;
				$pages->lastItemNumber   = $pages->firstItemNumber + $pages->currentItemCount - 1;
			}
	
			return $pages;
		}
	
		/**
		 * Nạp một kiểu phân trang
		 * @param string $_scrollingType
		 * @return Zend_Paginator_Scrolling_Interface
		 */
		protected function _loadScrolling($_scrollingType = null) {
			if ($_scrollingType === null) {
				$_scrollingType = self::$_prefixScrolling . self::$_defaultScrolling;
			}
			switch (strtolower(gettype($_scrollingType))) {
				case 'object':
					if (!$_scrollingType instanceof st_paginator_scrolling_interface) {
						return false;
					}
					if (null === $this->_scrolling) {
						$this->_scrolling = $_scrollingType;
					}
					return $this->_scrolling;
				case 'string':
					$_className = strtolower(self::$_prefixScrolling .$_scrollingType);
					if (!class_exists($_className)) {
						require_once APP_LIBRARY_PATH . 'tree/paginator/scrolling/' . $_className . '.php';	
					}
					if (null === $this->_scrolling) {
						$this->_scrolling = new $_className();
					}
					return $this->_scrolling;
				case 'null':
				default:
					return false;
			}
		}
		
		/**
		 * Sử dụng cấu hình trong một lần goi  phương thức
		 * @param class $_engine
		 * @param integer $_itemPerPage
		 * @param integer $_pageRange
		 * @param integer $_currentPageNumber
		 * @param string $_scrollingType
		 * @return Zend_Paginator_Scrolling_Interface
		 */
		public function setConfig($_config = array()) {
			if (!is_array($_config) || count($_config) == null) {
				throw new Exception("config must be array and not empty");
			}
			foreach ($_config as $_key => $_object) {
				$_method = 'set' . ucfirst($_key);
				$this->$_method($_object);
			}
			return $this;			
		}
	}
?>